#ifndef GAMEKIT_AutoPointer_H
#define GAMEKIT_AutoPointer_H

#include "../gamekit.h"

#include "SafePointer.h"

namespace gamekit
{
	template<typename T> class SafePointer;

	template<typename T>
	class GK_API AutoPointer
	{
	public:
		AutoPointer();
		AutoPointer(T* t);
		AutoPointer(const AutoPointer<T>& p);
		AutoPointer(const SafePointer<T>& p);
		~AutoPointer();

		AutoPointer& operator=(T* t);

		T* operator->() const;

		bool operator !() const;
		operator SafePointer<T>() const;
	    operator bool() const;

		inline friend bool operator==(const AutoPointer<T>& sp, const T* t)
		{
			return sp.m_t == t;
		}

		inline friend bool operator==(const T* t, const AutoPointer<T>& sp)
		{
			return t == sp.m_t;
		}

		inline friend bool operator!=(const AutoPointer<T>& sp, const T* t)
		{
			return sp.m_t != t;
		}

		inline friend bool operator!=(const T* t, const AutoPointer<T>& sp)
		{
			return t != sp.m_t;
		}

		template<typename U>
		inline friend bool operator==(const AutoPointer<T>& sp, const U* t)
		{
			return sp.m_t == t;
		}

		template<typename U>
		inline friend bool operator!=(const U* t, const AutoPointer<T>& sp)
		{
			return t != sp.m_t;
		}

		template<typename U>
		inline friend bool operator==(const AutoPointer<T>& sp, const AutoPointer<U>& su)
		{
			return sp.m_t == su.m_t;
		}

		template<typename U>
		inline friend bool operator!=(const AutoPointer<U>& su, const AutoPointer<T>& sp)
		{
			return su.m_t != sp.m_t;
		}

	private:
		T* m_t;
	};

	template<typename T>
	AutoPointer<T>::AutoPointer()
		: m_t(NULL)
	{
	}

	template<typename T>
	AutoPointer<T>::AutoPointer(const AutoPointer& p)
		: m_t(p.m_t)
	{
	}

	template<typename T>
	AutoPointer<T>::AutoPointer(T* t)
		: m_t(t)
	{
	}

	template<typename T>
	AutoPointer<T>::~AutoPointer()
	{
		if(m_t != NULL)
		{
			delete m_t;
			m_t = NULL;
		}
	}

	template<typename T>
	T* AutoPointer<T>::operator->() const
	{
		return m_t;
	}

	template<typename T>
	AutoPointer<T>& AutoPointer<T>::operator=(T* t)
	{
		if(m_t == t)
		{
			return *this;
		}

		if(m_t != NULL)
		{
			delete m_t;
		}

		m_t = t;
		return *this;
	}

	template<typename T>
	AutoPointer<T>::operator SafePointer<T>() const
	{
		return SafePointer<T>(m_t);
	}

	template<typename T>
	AutoPointer<T>::operator bool() const
	{
		return m_t != NULL;
	}

	template<typename T>
	bool AutoPointer<T>::operator !() const
	{
		return m_t == NULL;
	}
}

#endif